﻿//-----------------------------------------------------------------------
// <copyright file="CategoryListPresenter.cs" company="Forebrain Technology, LLC">
//
// Copyright (c) Forebrain Technology, LLC. All rights reserved.
// 
// This source code is released under the Microsoft Public License (Ms-PL).
//
// </copyright>
//-----------------------------------------------------------------------
namespace PivotCollectionMaker.WinFormApplication.Controls
{
    using System;
    using System.Windows.Forms;
    using PivotCollectionTools.Data;

    /// <summary>
    /// Present class to present the Pivot Table schema to a view.
    /// </summary>
    public class CategoryListPresenter
    {
        /// <summary>
        /// The interface to the view the presenter interacts with.
        /// </summary>
        private ICategoryListView view;

        /// <summary>
        /// Storage for the Pivot Table schema.
        /// </summary>
        private PivotTable model;

        /// <summary>
        /// Initializes a new instance of the <see cref="CategoryListPresenter"/> class.
        /// </summary>
        /// <param name="view">The view the preseneter interacts with.</param>
        /// <param name="table">The table to which the schema will be.</param>
        public CategoryListPresenter(ICategoryListView view, PivotTable table)
        {
            this.view = view;
            this.Model = table;

            this.view.CategoryItemSelected += new EventHandler(this.View_CategoryItemSelected);
            this.CreateCategoryPropertyBag();
        }

        /// <summary>
        /// Gets or sets the model.
        /// </summary>
        /// <value>The model of the category list presenter.</value>
        public PivotTable Model 
        {
            get
            {
                return this.model;
            }

            set
            {
                this.model = value;
                this.BindSchema();
            }
        }

        /// <summary>
        /// Adds the category.
        /// </summary>
        /// <param name="category">The category.</param>
        public void AddCategory(PivotTableCategory category)
        {
            this.Model.Categories.Add(category);
            this.view.AddCategoryListItem(category.Name);
        }

        /// <summary>
        /// Deletes the category.
        /// </summary>
        public void DeleteCategory()
        {
            if (this.view.SelectedCategoryIndex > this.model.Categories.Count)
            {
                return;
            }

            PivotTableCategory categoryToDelete = this.model.Categories[this.view.SelectedCategoryIndex];

            try
            {
                this.model.RemoveColumnsByCategory(categoryToDelete.Name);
            }
            catch (ArgumentOutOfRangeException e)
            {
                this.view.ShowMessage(e.Message, "Error.");
                return;
            }

            try
            {
                this.model.Categories.RemoveAt(this.view.SelectedCategoryIndex);
            }
            catch (ArgumentOutOfRangeException e)
            {
                this.view.ShowMessage(e.Message, "Error.");
                return;
            }
        }

        /// <summary>
        /// Adds a column to the schema.
        /// </summary>
        /// <returns>The new column added to the schema.</returns>
        public PivotTableColumn AddColumn()
        {
            string categoryName = this.model.Categories[this.view.SelectedCategoryIndex].Name;

            PivotTableColumn newColumn = null;
            try
            {
                newColumn = this.model.AddColumn(categoryName);
            }
            catch (ArgumentOutOfRangeException e)
            {
                this.view.ShowMessage(e.Message, "Error.");
            }

            if (newColumn == null)
            {
                return null;
            }

            this.view.AddColumnListItem(newColumn.Name);

            return newColumn;
        }

        /// <summary>
        /// Clears this instance.
        /// </summary>
        public void Clear()
        {
            this.model.Clear();
            this.view.ClearCategoryList();
        }

        /// <summary>
        /// Deletes the column.
        /// </summary>
        public void DeleteColumn()
        {
            if (!this.model.Columns.Contains(this.view.SelectedColumn))
            {
                return;
            }

            try
            {
                this.model.RemoveColumn(this.view.SelectedColumn);
            }
            catch (ArgumentOutOfRangeException e)
            {
                this.view.ShowMessage(e.Message, "Error.");
                return;
            }
        }

        /// <summary>
        /// Renames the category.
        /// </summary>
        /// <param name="newName">The new name.</param>
        public void RenameCategory(string newName)
        {
            PivotTableCategory pivotTableCategory = this.model.Categories[this.view.SelectedCategoryIndex];
            this.model.RenameCategory(pivotTableCategory, newName);
            this.BindSchema();
        }

        /// <summary>
        /// Creates the category property bag.
        /// </summary>
        public void CreateCategoryPropertyBag()
        {
            var properties = new PropertyBag();
            properties.Properties.Add(new PropertySpec("Name", typeof(string), "Category", "Determines whether the category appears in the filter panel. Can only be true for categories of type String, Number, or DateTime."));
            properties.Properties.Add(new PropertySpec("Format", typeof(string), "Category", "Optional .NET format string to be used for numeric types. It is recommended that data be rounded/truncated to match the format string to avoid potentially undesired behavior when filtering on that facet in the Pivot Graph View."));
            properties.Properties.Add(new PropertySpec("Data Type", typeof(PivotTableCellType), "Category", "Data Type"));

            properties.Properties.Add(new PropertySpec("Filter panel", typeof(Nullable<bool>), "Visable", "Determines whether the category appears in the filter panel. Can only be true for categories of type String, Number, or DateTime."));
            properties.Properties.Add(new PropertySpec("Keyword filter", typeof(Nullable<bool>), "Visable", "Determines whether the category is included in keyword filters over that collection. This attribute can only be true for categories of type String, LongString, or Link."));
            properties.Properties.Add(new PropertySpec("The info panel", typeof(Nullable<bool>), "Visable", "Determines whether the category is visible in the info panel."));
            
            properties.GetValue += new PropertySpecEventHandler(this.Properties_GetValue);
            properties.SetValue += new PropertySpecEventHandler(this.Properties_SetValue);

            this.view.ShowCategoryProperty(properties);
        }

        /// <summary>
        /// Prompts to rename category.
        /// </summary>
        /// <returns><c>True</c> if yes; otherwise, <c>false</c>.</returns>
        private bool PromptToRenameCategory()
        {
            if (this.view.AskQuestion("Rename Category?", "Rename") == DialogResult.No)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Updates the column list.
        /// </summary>
        /// <exception cref="IndexOutOfRangeException">
        ///     Selected index is out of range.
        /// </exception>
        private void UpdateColumnList()
        {
            if (this.view.SelectedCategoryIndex > this.model.Categories.Count)
            {
                return;
            }

            this.view.ClearColumnList();

            if (this.view.SelectedCategoryIndex < 0)
            {
                return;
            }

            if (this.model.Categories[this.view.SelectedCategoryIndex] == null)
            {
                return;
            }

            foreach (var column in this.model.Categories[this.view.SelectedCategoryIndex].Columns)
            {
                this.view.AddColumnListItem(column.Name);
            }
        }

        /// <summary>
        /// Binds the schema.
        /// </summary>
        private void BindSchema()
        {
            if (this.view == null)
            {
                return;
            }

            this.view.ClearCategoryList();

            foreach (var item in this.Model.Categories)
            {
                this.view.AddCategoryListItem(item.Name);
            }
            this.view.RefreshProperties();
            UpdateColumnList();
        }

        /// <summary>
        /// Handles the CategoryItemSelected event of the view control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void View_CategoryItemSelected(object sender, EventArgs e)
        {
            this.UpdateColumnList();
        }

        /// <summary>
        /// Handles the SetValue event of the properties control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.PropertySpecEventArgs"/> instance containing the event data.</param>
        private void Properties_SetValue(object sender, PropertySpecEventArgs e)
        {
            if (this.view.SelectedCategoryIndex <= 0)
            {
                return;
            }

            PivotTableCategory selectedCategory = this.model.Categories[this.view.SelectedCategoryIndex];

            switch (e.Property.Name)
            {
                case "Filter panel":
                    selectedCategory.IsFilterVisible = (Nullable<bool>)e.Value;
                    break;
                case "Keyword filter":
                    selectedCategory.IsWordWheelVisible = (Nullable<bool>)e.Value;
                    break;
                case "The info panel":
                    selectedCategory.IsMetadataVisible = (Nullable<bool>)e.Value;
                    break;
                case "Format":
                    selectedCategory.Format = (string)e.Value;
                    break;
                case "Name":
                    if (this.PromptToRenameCategory())
                    {
                        this.RenameCategory((string)e.Value);
                    }

                    break;
                case "Data Type":
                    selectedCategory.ValueType = (PivotTableCellType)e.Value;
                    break;
            }
        }

        /// <summary>
        /// Handles the GetValue event of the properties control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="PivotCollectionMaker.WinFormApplication.PropertySpecEventArgs"/> instance containing the event data.</param>
        private void Properties_GetValue(object sender, PropertySpecEventArgs e)
        {
            if (this.view.SelectedCategoryIndex < 0)
            {
                return;
            }

            PivotTableCategory selectedCategory = this.model.Categories[this.view.SelectedCategoryIndex];

            switch (e.Property.Name)
            {
                case "Filter panel":
                    e.Value = selectedCategory.IsFilterVisible;
                    break;
                case "Keyword filter":
                    e.Value = selectedCategory.IsWordWheelVisible;
                    break;
                case "The info panel":
                    e.Value = selectedCategory.IsMetadataVisible;
                    break;
                case "Format":
                    e.Value = selectedCategory.Format;
                    break;
                case "Name":
                    e.Value = selectedCategory.Name;
                    break;
                case "Data Type":
                    e.Value = selectedCategory.ValueType;
                    break;
            }
        }
    }
}
